const event = Object.create(null)
const registry  = (exp, fn) => {
  if (typeof exp !== 'string' || !(exp.length >>> 0)) throw new Error('unkonow expression')
  if (typeof fn !== 'function') throw new Error('fn is not a function')
  else if ('[object AsyncFunction]' !== Object.prototype.toString.call(fn)) throw new Error('fn is required a async function')
  if (!event[exp] || !event[exp].length) event[exp] = []
  event[exp].push(fn)
}
const compose = mids => {
  let index = -1
  const dispatch = i => {
    if (i <= index) return Promise.reject(new Error('no more handler, next can only called once in each handler'))
    index = i
    let fn
    if (i === mids.length) fn = void +0
    else fn = mids[i]
    if (!fn) return Promise.resolve()
    return Promise.resolve(fn(() => dispatch(i + 1)))
  }
  return dispatch(0)
}
const trigger = (exp, ctrl) => {
  if (typeof exp !== 'string') throw new Error('unkonow expression')
  return emit(exp, ctrl)
}
const emit = (exp, ctrl) => {
  if (ctrl) {
    for (let [k, v] of event[exp].entries()) {
      Promise.resolve().then(() => {v()})
    }
  } else {
    compose(event[exp])
  }
}
module.exports = {
  registry,
  trigger
}
